<template>
    <el-cascader v-model="currentValue"
                 :options="optionData"
                 :props="myProps"
                 :size="size"
                 :placeholder="placeholder"
                 :disabled="disabled"
                 :clearable="clearable"
                 :show-all-levels="showAllLevels"
                 :collapse-tags="collapseTags"
                 :separator="separator"
                 :filterable="filterable"
                 :filter-method="filterMethod"
                 :debounce="debounce"
                 :before-filter="beforeFilter"
                 :popper-class="popperClass"
                 @input="handleInput"
                 @change="handleChange"
                 @expand-change="handleExpandChange"
                 @blur="handleBlur"
                 @focus="handleFocus"
                 @visible-change="handleVisibleChange"
                 @remove-tag="handleRemoveTag">
        <slot></slot>
    </el-cascader>
</template>

<script>
export default {
  props: {
    // 选中项绑定值
    value: {
      type: [Array, Number, String]
    },
    // 可选项数据源，键名可通过 Props 属性配置
    options: {
      type: Array,
      required: true
    },
    props: {
      type: Object
    },
    // 尺寸
    size: {
      type: String,
      default: ''
    },
    // 输入框占位文本
    placeholder: {
      type: String,
      default: '请选择'
    },
    // 是否禁用
    disabled: Boolean,
    // 是否支持清空选项
    clearable: {
      type: Boolean,
      default: true
    },
    // 输入框中是否显示选中值的完整路径
    showAllLevels: {
      type: Boolean,
      default: false
    },
    // 多选模式下是否折叠Tag
    collapseTags: {
      type: Boolean,
      default: false
    },
    // 选项分隔符
    separator: {
      type: String,
      default: '/'
    },
    // 是否可搜索选项
    filterable: Boolean,
    // 自定义搜索逻辑
    filterMethod: {
      type: Function,
      // 第一个参数是节点node，第二个参数是搜索关键词keyword，通过返回布尔值表示是否命中
      default: function (node, keyword) {}
    },
    // 搜索关键词输入的去抖延迟，毫秒
    debounce: Number,
    // 筛选之前的钩子，参数为输入的值，若返回 false 或者返回 Promise 且被 reject，则停止筛选
    beforeFilter: {
      type: Function
    },
    // 自定义浮层类名
    popperClass: String,
    enableRootEmptyChild: {
      type: Boolean,
      default: true
    },
    // 简单值，非递进式数组
    singleValue: {
      type: Boolean,
      default: true
    },
    // 排除不显示的项
    exceptionOptionValues: {
      type: [String, Number, Array],
      default () {
        return []
      }
    }
  },
  data () {
    return {
      currentValue: this.value || [],
      hashData: {},
      optionData: []
    }
  },
  watch: {
    // 选项更新
    options (newVal) {
      this.setOptions()
    },
    // 选中值发生变化时
    currentValue (newVal) {},
    // 设定值发生变化时
    value (newVal) {
      this.setCurrentValue(newVal)
    }
  },
  computed: {
    myProps () {
      var props = this.props || {}

      return {
        // 次级菜单的展开方式,click / hover
        expandTrigger: props.expandTrigger || 'click',
        // 是否多选
        multiple: typeof (props.multiple) === 'boolean' ? props.multiple : false,
        // 是否严格的遵守父子节点不互相关联
        checkStrictly: typeof (props.checkStrictly) === 'boolean' ? props.checkStrictly : true,
        // 在选中节点改变时，是否返回由该节点所在的各级菜单的值所组成的数组，若设置 false，则只返回该节点的值
        emitPath: typeof (props.emitPath) === 'boolean' ? props.emitPath : true,
        // 是否动态加载子节点，需与lazyLoad方法结合使用
        lazy: typeof (props.lazy) === 'boolean' ? props.lazy : false,
        // 加载动态数据的方法，仅在 lazy 为 true 时有效
        lazyLoad: props.lazyLoad || function (node, resolve) {
          // node为当前点击的节点，resolve为数据加载完成的回调(必须调用)
        },
        // 指定选项的值为选项对象的某个属性值
        value: props.value || 'value',
        // 指定选项标签为选项对象的某个属性值
        label: props.label || 'label',
        // 指定选项的子选项为选项对象的某个属性值
        children: props.children || 'children',
        // 指定选项的禁用为选项对象的某个属性值
        disabled: props.disabled || 'disabled',
        // 指定选项的叶子节点的标志位为选项对象的某个属性值
        leaf: props.leaf || 'leaf',
        // 子从关系的父指向属性
        parentNodeKey: props.parentNodeKey || 'ParentId'
      }
    },
    // 需要排除的项列表
    exceptionOptionValuesArray () {
      return Object.prototype.toString.call(this.exceptionOptionValues) !== '[object Array]' ? [this
        .exceptionOptionValues
      ] : this.exceptionOptionValues
    }
  },
  methods: {
    // cascader内赋值的时候触发
    handleInput (newVal) {
      let value = [].concat(newVal)

      if (this.myProps.multiple) {
        // 如果是启用复选
        if (this.singleValue) {
          for (var i = 0; i < value.length; i++) {
            value[i] = [].concat(value[i]).pop()
          }
        }
      } else {
        // 单选
        if (this.singleValue) {
          value = value.pop()
        }
      }

      this.$emit('input', value)
    },
    // 当选中节点变化时触发
    // val:选中节点的值
    handleChange (newVal) {
      let value = [].concat(newVal)

      if (this.myProps.multiple) {
        // 如果是启用复选
        if (this.singleValue) {
          for (var i = 0; i < value.length; i++) {
            value[i] = [].concat(value[i]).pop()
          }
        }
      } else {
        // 单选
        if (this.singleValue) {
          value = value.pop()
        }
      }

      this.$emit('change', value)
    },
    // 当展开节点发生变化时触发
    handleExpandChange () {

    },
    // 当失去焦点时触发
    handleBlur () {

    },
    // 当获得焦点时触发
    handleFocus () {

    },
    // 下拉框出现/隐藏时触发
    handleVisibleChange () {

    },
    // 在多选模式下，移除Tag时触发
    handleRemoveTag () {

    },
    // 解析选项数组
    analysisOptions (options, fromParent, parentValue) {
      options = options || []

      // 遍历数组
      options.forEach(item => {
        let optionsValue = item[this.myProps.value]

        // 如果存在排除的项，则跳过
        if (this.exceptionOptionValuesArray.indexOf(optionsValue) > -1) {
          return
        }

        this.hashData[optionsValue] = item

        if (fromParent == true) {
          item[this.myProps.parentNodeKey] = parentValue
        }

        // 存在children，则继续遍历，填充hashData
        if (Object.prototype.toString.call(item[this.myProps.children]) === '[object Array]' &&
                        item[this.myProps.children].length > 0) {
          if (fromParent != true) {
            this.optionData.push(item)
          }

          this.analysisOptions(item[this.myProps.children], true, item[this.myProps.value])
        } else if (fromParent != true) {
          if (
            item[this.myProps.parentNodeKey] == 0 ||
                            item[this.myProps.parentNodeKey] == '0' ||
                            item[this.myProps.parentNodeKey] == '' ||
                            item[this.myProps.parentNodeKey] === undefined) {
            if (
              this.enableRootEmptyChild == false &&
                                item[this.myProps.children] === undefined
            ) {
              item[this.myProps.children] = []
            }

            this.optionData.push(item)
          } else {
            let hashKey = item[this.myProps.parentNodeKey]

            if (this.hashData[hashKey]) {
              this.hashData[hashKey][this.myProps.children] =
                                    this.hashData[hashKey][this.myProps.children] || []

              if (
                this.hashData[hashKey][this.myProps.children].indexOf(
                  item
                ) == -1
              ) {
                this.hashData[hashKey][this.myProps.children].push(item)
              }
            }
          }
        }
      })
    },
    setOptions () {
      this.hashData = {}
      this.optionData = []
      this.analysisOptions(this.options)
      this.setCurrentValue(this.value)
    },
    createFullValue (newVal) {
      let hashData = this.hashData
      let value = [newVal]

      // 循环遍历，判断父级菜单存不存在
      let parentValue =
                    (hashData[newVal] &&
                        hashData[newVal][this.myProps.parentNodeKey]) ||
                    ''
      while (parentValue != '' && parentValue != '0') {
        value.unshift(parentValue)
        parentValue =
                        (hashData[parentValue] &&
                            hashData[parentValue][this.myProps.parentNodeKey]) ||
                        ''
      }

      return value
    },
    // 拼装组成递进式值数组
    pieceValue (newVal) {
      var value = []

      let hashData = this.hashData
      value = [newVal]

      // 循环遍历，判断父级菜单存不存在
      let parentValue =
                    (hashData[newVal] &&
                        hashData[newVal][this.myProps.parentNodeKey]) ||
                    ''

      while (parentValue != '' && parentValue != '0') {
        value.unshift(parentValue)
        parentValue =
                        (hashData[parentValue] &&
                            hashData[parentValue][this.myProps.parentNodeKey]) ||
                        ''
      }

      return value
    },
    // 设置当前选择的值
    setCurrentValue (newVal) {
      let value = []
      // 复选
      if (this.myProps.multiple) {
        if (Object.prototype.toString.call(newVal) != '[object Array]') {
          newVal = [newVal]
        }

        // 复选功能，遍历初始值
        newVal.forEach(val => {
          if (Object.prototype.toString.call(val) != '[object Array]') {
            val = this.pieceValue(val)
          }

          value.push(val)
        })
      }
      // 单选
      else {
        if (this.singleValue) {
          value = this.pieceValue(newVal)
        } else {
          if (Object.prototype.toString.call(newVal) != '[object Array]') {
            value = [newVal]
          }

          value = newVal
        }
      }

      this.currentValue = value
    }
  },
  created () {
    this.setOptions()
    this.setCurrentValue(this.value)
  }
}
</script>


<style scoped>
.el-cascader{
  display: block !important;
}
</style>